#include <iostream>

#include "renderer.hpp"

SampleInfo::SampleInfo():
  depth(0), prevSample(0), prim(0), ray(Vector3(), Vector3())
{}

Renderer::Renderer(int width, int height, const char *filename)
{
	width_ = width;
	height_ = height;
	filename_ = filename;
	raster_ = new Raster(width, height);

	time(&lastSaveTime_);
};

Renderer::~Renderer()
{
	delete raster_;
}

bool Renderer::timeToWrite()
{
	time_t currentTime;
	time(&currentTime);

	if((currentTime - lastSaveTime_) > 10) //write file every 10 seconds
	{
		lastSaveTime_ = currentTime;
		return true;
	}
	return false;
}

void Renderer::render(const Scene& scene)
{
	// defining camera and making some precalculations
	// TODO: this code need to be moved to Camera class or somewhere else!
	int passes = 4; // FIXME!!!  magic number

	SampleInfo sample;

	Vector3 tl = Vector3(-1.0, 1.0, 1.0);
	Vector3 tr = Vector3(1.0, 1.0, 1.0);
	Vector3 bl = Vector3(-1.0, -1.0, 1.0);
	Vector3 br = Vector3(1.0, -1.0, 1.0);
	double mx = width_ - 1;
	double my = height_ - 1;
	Vector3 jx = (tr - tl) * (1.0 / width_);
	Vector3 jy = (tr - br) * (1.0 / height_);

	// rendering
	for(int currentPass = 1; currentPass <= passes; currentPass++)
	{
		cout << "pass #" << currentPass << endl;
		for(int y = 0; y < height_; y++)
		{
			for(int x = 0; x < width_; x++)
			{
				// find current ray for raytracing by interpolating between
				// 4 camera corner vectors
				Vector3 v = tl * ((mx - x) * (my - y) / (mx * my));
				v = v + tr * (x * (my - y) / (mx * my));
				v = v + bl * ((mx - x) * y / (mx * my));
				v = v + br * (x * y / (mx * my));
				// add jitter
				Ray ray = Ray(Vector3(0.0, 0.0, 0.0), v + jx * ((double)rand() / (double) RAND_MAX) + jy * ((double)rand() / (double) RAND_MAX));
				// trace current ray
				Color color = raytrace(ray, sample, scene);
				// and add recieved color to accum
				raster_->setPixel(x, y, color * (1.0 / currentPass) + raster_->getPixel(x, y) * ((currentPass - 1.0) / currentPass));
			}
		}
		if(timeToWrite())
		{
			cout << "Writing bitmap to """ << filename_ << """" << endl;
//			raster_->writePPM(filename_);
		}
	}
//	raster_->writePPM(filename_);
}

Color Renderer::raytrace(const Ray& ray_, const SampleInfo& prevSample, const Scene& scene) const
{
	if(prevSample.depth >= 6) // FIXME!!!  magic number
		return Color(0.0, 0.0, 0.0);
	
	Scene::PrimIter intersectionPrim = scene.end();	
	double dist = 1e300; // FIXME!!!  magic number
	SampleInfo sample;

	Ray ray = ray_;
	ray.origin_ = ray_.origin_ + ray_.direction_ * 0.00000001; // FIXME!!!  magic number

	for(Scene::PrimIter i = scene.begin(); i != scene.end(); i++)
	{
		if((*i)->intersect(ray, dist, sample))
		{
			intersectionPrim = i;
			dist = sample.dist;
		}
	}
	if(intersectionPrim == scene.end())
		return Color(0.0, 0.0, 0.0);

	sample.depth = prevSample.depth + 1;
	sample.position = ray.getOrigin() + ray.getDirection() * dist;
	sample.ray = ray;
	sample.prim = (*intersectionPrim);
	sample.prevSample = &sample;

	return (*intersectionPrim)->shade(sample, scene, *this);
}
